#include <mpi.h>

#include "GRASP.h"
#include "Kruskal.h"
#include "FileSTS.h"



double startwtime = 0.0, endwtime;
int melhorIter = 0;


int main(int argc, char** argv){
	if(argc == 4){
		int size, rank;
		MPI_Status status;
	 
		MPI_Init(&argc, &argv);
		MPI_Comm_size(MPI_COMM_WORLD, &size);
		MPI_Comm_rank(MPI_COMM_WORLD, &rank);
	
                
                int MAX_ITER = 120;
                int CALCULO_ITER = MAX_ITER/size;
                int RESTO = MAX_ITER%size;
                
                if(rank < RESTO){
                    CALCULO_ITER++;
                }
                
		srand(time(NULL));
		
		//Inicializando os dados de arquivo
		Solucao::loadEntrada(argv[1]);
		double alpha = atof(argv[2]);
		GRASP g(Solucao::tamanho, alpha);
		
		//Pegando o tempo inicial
		if(rank == 0)
			startwtime = MPI_Wtime();

		
                SolucaoGRASPSTS *sbest = NULL;
                printf("Processo %d fazendo %d iteracoes\n",rank, CALCULO_ITER);
                
		for(int i=0; i< CALCULO_ITER; i++){
			//Fase de Construcao e Busca Local.
			SolucaoGRASPSTS *sol = g.construcao();
			SolucaoGRASPSTS *sbl = g.descida(sol);
			delete sol;
			//Executando o VNS.
			SolucaoGRASPSTS *svns = g.ILS(sbl);
			
			if(sbest == NULL){
				sbest = svns;
				melhorIter = i;
			}else{
				if(svns->avaliacao < sbest->avaliacao){
					delete sbest;
					sbest = svns;
					melhorIter = i;
				}else
					delete svns;
			}
		}
	
		char *data = NULL;
		double aval;
		//SolucaoGRASPSTS *svns = sbl;

		//Sincroniza��o dos Resultados
		if(rank == 0){
			data = new char[Solucao::tamanho + 1];
			//Recebendo dos clientes.
			for(int j=1; j<size; j++){
				MPI_Recv(data, (Solucao::tamanho + 1), MPI_CHAR, MPI_ANY_SOURCE, 4, MPI_COMM_WORLD, &status);
				MPI_Recv(&aval, 1, MPI_DOUBLE, MPI_ANY_SOURCE, 5, MPI_COMM_WORLD, &status);
				if(aval < sbest->avaliacao){
					delete sbest;
					sbest = new SolucaoGRASPSTS(data);
					sbest->avaliacao = aval;
				}
			}
			delete data;
		}else{
			data = sbest->print();
			//Enviando a sua melhor solucao para o servidor.
			MPI_Send(data, (Solucao::tamanho + 1), MPI_CHAR, 0, 4, MPI_COMM_WORLD);
			MPI_Send(&sbest->avaliacao, 1, MPI_DOUBLE, 0, 5, MPI_COMM_WORLD);
			delete sbest;
		}

		if(rank == 0){
			endwtime = MPI_Wtime();
			FileSTS::printInstancia(argv[3], size, alpha, sbest->tamanho, sbest->numClient, melhorIter, sbest->avaliacao, (int)((endwtime - startwtime) * 1000));
			printf("Final: %s F: %f Tempo: %f\n", sbest->print(), sbest->avaliacao, endwtime - startwtime);
		}
		
	}else{
		puts("<usage: grasp nameFile alpha estrategia>");
	}
	MPI_Finalize();
	return 0;
}

